﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace GiveAQuiz.Data
{
  /// <summary>
  /// This class implements the data storage exposed by 
  /// by the IQuizRepository using the Entity Framework.
  /// </summary>
  public class QuizRepository : IQuizRepository
  {
    /// <summary>
    /// Gets a listing of Quizzes for a given User.
    /// </summary>
    /// <param name="userKey">The user to search for.</param>
    /// <returns>An Enumeration of QuizDefinition objects 
    /// for the specified User.</returns>
    public IEnumerable<QuizDefinition> GetUserQuizDefinitions(Guid userKey)
    {
      return Context.QuizDefinitions
                    .Include("Quizzes")
                    .Where(q => q.Owner == userKey)
                    .OrderBy(q => q.QuizName)
                    .ToList();
    }

    /// <summary>
    /// Retrieve a QuizDefinition from the underlying data storage
    /// by the specified id.
    /// </summary>
    /// <param name="quizDefinitionId">The id of the QuizDefinition 
    /// to retrieve.</param>
    /// <returns>The corresponding QuizDefinition object.</returns>
    public QuizDefinition GetQuizDefintion(int quizDefinitionId)
    {
      return Context.QuizDefinitions.First(qd => qd.Id == quizDefinitionId);
    }


    /// <summary>
    /// Retrieve a Quiz from the underlying data storage
    /// by the specified id.
    /// </summary>
    /// <param name="quizId">The id of the Quiz to retrieve.</param>
    /// <returns></returns>
    public Quiz GetQuiz(int quizId)
    {
      return Context.Quizzes.First(q => q.Id == quizId);
    }

    /// <summary>
    /// Retrieves a Quiz from the underlying data storage
    /// by its passphrase.
    /// </summary>
    /// <param name="passphrase">The passphrase to search on.</param>
    /// <returns>The corresponding Quiz object if found; otherwise null.</returns>
    public Quiz GetQuizByPassphrase(string passphrase)
    {
      return Context.Quizzes.FirstOrDefault(q => q.Password.Equals(passphrase));
    }

    /// <summary>
    /// Save a QuizResult in the underlying data storage.
    /// </summary>
    /// <param name="quizResult">The result to save.</param>
    public void SaveQuizResult(QuizResult quizResult)
    {
      Context.AddToQuizResults(quizResult);
      Context.SaveChanges();
    }

    /// <summary>
    /// Retrieve a QuizResult from the underlying data storage
    /// by the specified id.
    /// </summary>
    /// <param name="quizResultId">The id of the QuizResult to 
    /// retrieve.</param>
    /// <returns>The corresponding QuizResult object.</returns>
    public QuizResult GetQuizResult(int quizResultId)
    {
      return Context.QuizResults.First(qr => qr.Id == quizResultId);
    }

    /// <summary>
    /// Saves a new Quiz User to the database.
    /// </summary>
    /// <param name="quizUser">The new Quiz User</param>
    public void SaveUser(QuizUser quizUser)
    {
      Context.AddToQuizUsers(quizUser);
      Context.SaveChanges();
    }

    /// <summary>
    /// Save a Quiz in the underlying data storage.
    /// </summary>
    /// <param name="quiz">The Quiz to save.</param>
    public void SaveQuiz(Quiz quiz)
    {
      Context.AddToQuizzes(quiz);
      Context.SaveChanges();
    }

    /// <summary>
    /// Updates a Quiz in the underlying data storage.
    /// </summary>
    /// <param name="quiz">The quiz to update.</param>
    public void UpdateQuiz(Quiz quiz)
    {
      Context.Quizzes.ApplyCurrentValues(quiz);
      Context.SaveChanges();
    }

    /// <summary>
    /// Delete a Quiz from the underlying data storage by its
    /// specified id.
    /// </summary>
    /// <param name="id">The id of the Quiz to delete.</param>
    public void DeleteQuiz(int id)
    {
      var quiz = Context.Quizzes.FirstOrDefault(q => q.Id == id);

      if ( quiz != null )
      {
        Context.DeleteObject(quiz);
        Context.SaveChanges();
      }
    }

    /// <summary>
    /// Delete a QuizDefinition from the underlying data storage by the
    /// specified id.
    /// </summary>
    /// <param name="id">The id of the QuizDefintion to delete.</param>
    public void DeleteQuizDefinition(int id)
    {
      var quizDef = Context.QuizDefinitions.FirstOrDefault(qd => qd.Id == id);

      if ( quizDef != null )
      {
        Context.DeleteObject(quizDef);
        Context.SaveChanges();
      }
    }

    /// <summary>
    /// Delete all the results for a given Quiz.
    /// </summary>
    /// <param name="quizId">The ID of the Quiz.</param>
    public void DeleteQuizResults(int quizId)
    {
      var results = Context.QuizResults.Where(qr => qr.QuizKey == quizId);

      foreach ( var qr in results )
      {
        Context.DeleteObject(qr);
      }

      Context.SaveChanges();
    }

    // Deferred construction of the Context
    GiveAQuizEntities _ctx = null;
    GiveAQuizEntities Context
    {
      get { return _ctx ?? (_ctx = new GiveAQuizEntities()); }
    }
  }
}
